#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
#include "protocol.h"
#include "usart.h"
#include "can_driver.h"
#include "frame_driver.h"
#include "common_driver.h"
#include "protocol_command.h"
#include "system.h"
#include "data.h"
#include "memory.h"

extern osMessageQId nQueueReceiveHandle;
extern osMessageQId nQueueTransferHandle;

uint8_t Protocol_FrameSendBuffer0[dFrame_LengthMax] = {0};
static Protocol_CommunicationMode_EnumDef CommunicationMode = eCommunicationMode_CAN;//通信方式
bool OperationInformationPrintf = false; 

int fputc(int ch,FILE *f)
{
    if(!OperationInformationPrintf)return ch;
	unsigned char temp[1] = {ch};
    // 等待发送缓冲区为空
    while (!(USART1->SR & USART_SR_TXE));
	HAL_UART_Transmit(&huart1,temp,1,2);
    // 等待发送完成
    while (!(USART1->SR & USART_SR_TC));
	return(ch);
}

/****************************************************
@function:向队列写入数据
@param:
    QueueHandle:队列句柄
    interrupt:真-中断场景,假-非中断场景
    buf:帧数据
    len:数据长度
@return:接收数据缓存状态
    0-数据缓存成功\
    -1-参数错误
    -2-队列写入失败
    负数-数据缓存失败
@note:
    含操作函数时数据直接写入队列，否则直接解析帧数据
****************************************************/
static int32_t Protocol_QueueWriteData(osMessageQId QueueHandle,bool interrupt,uint8_t *buf,uint32_t len)
{
    if((buf == NULL) || (len == 0))return -1;
    BaseType_t HigherPriorityTaskWoken;
    for(uint32_t i = 0;i < len;i++)
    {
        if(interrupt)
        {
            if(xQueueSendFromISR(QueueHandle,( void * )(buf + i),&HigherPriorityTaskWoken) != pdTRUE)
            {
                //dLOG("xQueueSend error\r\n");
                return -2;
            }
        }
        else
        {
            if(xQueueSend(QueueHandle,( void * )(buf + i),100) != pdTRUE)
            {
                //dLOG("xQueueSend error\r\n");
                return -2;
            }
        }
    }
    return 0;
}

//mode为接收数据来源方式
int32_t Protocol_Receive(Protocol_CommunicationMode_EnumDef mode,bool interrupt,uint8_t *buf,uint32_t len){CommunicationMode = mode;return Protocol_QueueWriteData(nQueueReceiveHandle,interrupt,buf,len);}
int32_t Protocol_Transfer(bool interrupt,uint8_t *buf,uint32_t len){return Protocol_QueueWriteData(nQueueTransferHandle,interrupt,buf,len);}

/****************************************************
@function:设备数据发送接口函数
@param:
    interrupt:真-中断场景，假-非中断场景
    buf:数据缓冲区
    len:数据字节数
@return:0-发送成功，否则发送失败
@note:
****************************************************/
int32_t Protocol_DataTransmit(bool interrupt,uint8_t *buf,uint32_t len)
{
    uint32_t residue = len,number = 0,pos = 0;
    while((residue > 0))
    {
        if(CommunicationMode == eCommunicationMode_CAN)
        {
            number = (residue > 8)?8:residue;
            can_SendDataInterface(&hcan,(buf + pos),number);
            osDelay(1);
        }
        else
        {
            number = (residue > 2048)?2048:residue;
            while (!(huart1.Instance->SR & USART_SR_TXE));// 等待发送缓冲区为空
            HAL_UART_Transmit_DMA(&huart1,(const uint8_t *)(buf + pos),number);
            while(!(huart1.Instance->SR & (0x01 << 6)))osDelay(1);//判断TC发送完成标志
        }
        residue -= number;
        pos += number;
    }
    return 0;
}

/****************************************************
@function:接收用户传输协议解析
@param:
    frame_address:帧起始地址
    frame_len:帧字节数
    data_address:帧数据段起始地址
    data_len:帧数据段字节数
@return:void
@note:
****************************************************/
void Protocol_FrameAnalysis(uint8_t *frame_address,uint32_t frame_len,uint8_t *data_address,uint32_t data_len)
{
    uint8_t sum = frame_ChecksumGet(frame_address,frame_len-1);
    if(sum != frame_address[frame_len-1])return;
    if((data_address[1] != System_BoardAddressGet()) && (data_address[1] != eDeviceAddress_Broadcast))return;//非本设备帧命令
    uint8_t cmd = data_address[2],code = data_address[3],value = 0;
    uint16_t pos = 4;
    bool state;

    switch(cmd)
    {
        case eCommandType_Device:
        {
            switch(code)
            {
                case eCodeType_Device_SystemReset_Request:
                {
                    dLOG("SystemReset_Request\n");
                    Protocol_CommandSend_General_NullValue(false,Protocol_FrameSendBuffer0,eCommandType_Device,eCodeType_Device_SystemReset_Ack);
                    osDelay(30);//避免应答命令未发送结束
                    Common_SystemReset_Monitor(true);
                }break;
                case eCodeType_Device_SystemRestore_Request:
                {
                    dLOG("SystemRestore_Request\n");
                    Protocol_CommandSend_General_NullValue(false,Protocol_FrameSendBuffer0,eCommandType_Device,eCodeType_Device_SystemRestore_Ack);
                    state = Data_CalibrationDataUse_Get();
                    Data_CalibrationDataUse_Set(false);
                    Data_SystemRestore();
                    Data_CalibrationDataUse_Set(state);
                    osDelay(30);//避免应答命令未发送结束
                    Common_SystemReset_Monitor(true);
                }break;
                case eCodeType_Device_Address_Set:
                {
                    value = data_address[pos++];
                    Protocol_CommandSend_General_NullValue(false,Protocol_FrameSendBuffer0,eCommandType_Device,eCodeType_Device_Address_Ack);
                    state = Data_CalibrationDataUse_Get();
                    Data_CalibrationDataUse_Set(false);
                    Data_DeviceAddress_Set(value);
                    Data_CalibrationDataUse_Set(state);
                    dLOG("Address_Set:%d\n",value);
                }break;
                case eCodeType_Device_Sample_Query:
                {
                    float temperature = 0.0f,concentration = 0.0f,VoltageTemperature = 0.0f,VoltageHydrogen = 0.0f;
                    Data_DeviceSampleResult_Get(&temperature,&concentration,&VoltageTemperature,&VoltageHydrogen);
                    dLOG("Sample_Query:T=%.2f C=%.2f VT=%.3fV VH2=%.3f\n",temperature,concentration,VoltageTemperature,VoltageHydrogen);
                    Protocol_CommandSend_Device_Sample_Ack(false,Protocol_FrameSendBuffer0,temperature,concentration,VoltageTemperature,VoltageHydrogen);
                }break;
                case eCodeType_Device_CalibrationDataUse_Set:
                {
                    value = data_address[pos++];
                    dLOG("CalibrationDataUse_Set:Use=%s\n",(value?"True":"False"));
                    Data_CalibrationDataUse_Set(value?true:false);
                    Protocol_CommandSend_General_NullValue(false,Protocol_FrameSendBuffer0,eCommandType_Device,eCodeType_Device_CalibrationDataUse_Ack);
                }break;
                case eCodeType_Device_CalibrationDataLoad_Request:
                {
                    dLOG("CalibrationDataLoad_Request\n");
                    state = Data_CalibrationDataUse_Get();
                    Data_CalibrationDataUse_Set(false);
                    Data_CalibrationLoad();
                    Data_CalibrationDataUse_Set(state);
                    Protocol_CommandSend_General_NullValue(false,Protocol_FrameSendBuffer0,eCommandType_Device,eCodeType_Device_CalibrationDataLoad_Ack);
                }break;
                case eCodeType_Device_CalibrationDataDelete_Request:
                {
                    value = data_address[pos++];
                    dLOG("CalibrationDataDelete_Request:%s\n",dMemory_FileName(value));
                    state = Data_CalibrationDataUse_Get();
                    Data_CalibrationDataUse_Set(false);
                    Memory_FileLineNumber_Write((Memory_FileObject_EnumDef )value,0);
                    Data_CalibrationDataUse_Set(state);
                    Protocol_CommandSend_General_NullValue(false,Protocol_FrameSendBuffer0,eCommandType_Device,eCodeType_Device_CalibrationDataDelete_Ack);
                }break;
                case eCodeType_Device_FilePrintf_Request:
                {
                    value = data_address[pos++];
                    dLOG("FilePrintf_Request:%s\n",dMemory_FileName(value));
                    state = Data_CalibrationDataUse_Get();
                    Data_CalibrationDataUse_Set(false);
                    Memory_FileDataPrintf((Memory_FileObject_EnumDef )value);
                    Data_CalibrationDataUse_Set(state);
                    Protocol_CommandSend_General_NullValue(false,Protocol_FrameSendBuffer0,eCommandType_Device,eCodeType_Device_FilePrintf_Ack);
                }break;
                case eCodeType_Device_FileTransmit_Request:
                {
                    value = data_address[pos++];
                    dLOG("FileTransmit_Request:%s\n",dMemory_FileName(value));
                    state = Data_CalibrationDataUse_Get();
                    Data_CalibrationDataUse_Set(false);
                    Protocol_CommandSend_FileTransmit(false,Protocol_FrameSendBuffer0,sizeof(Protocol_FrameSendBuffer0),value);
                    Data_CalibrationDataUse_Set(state);
                }break;
                case eCodeType_Device_FileTransmit_Data:
                {
                    uint8_t object = 0;
                    uint16_t index = 0,FrameLineNumber = 0;
                    object = data_address[pos++];
                    index = data_address[pos++];index <<= 8;//高8位
                    index |= data_address[pos++];//低8位
                    FrameLineNumber = data_address[pos++];FrameLineNumber <<= 8;//高8位
                    FrameLineNumber |= data_address[pos++];//低8位
                    
                    dLOG("FileTransmit_Data:object=%s index=%d FrameLineNumber=%d\n",dMemory_FileName(object),index,FrameLineNumber);
                    if((object != eMemory_FileObject_User0) || (FrameLineNumber == 0) || (index >= dMemory_FileLineNumberMax_User0) || (FrameLineNumber > dMemory_FileLineNumberMax_User0)){Protocol_CommandSend_General_OneValue(false,Protocol_FrameSendBuffer0,eCommandType_Device,eCodeType_Device_FileTransmit_DataAck,1);return;}
                    state = Data_CalibrationDataUse_Get();
                    Data_CalibrationDataUse_Set(false);
                    Memory_FileContent_Write((Memory_FileObject_EnumDef )object,index,(void *)(data_address+pos),FrameLineNumber);
                    Data_CalibrationDataUse_Set(state);
                    Protocol_CommandSend_General_OneValue(false,Protocol_FrameSendBuffer0,eCommandType_Device,eCodeType_Device_FileTransmit_DataAck,0);
                }break;
                case eCodeType_Device_FileTransmit_Finish:
                {
                    uint8_t object = 0;
                    uint16_t LineNumber = 0;
                    object = data_address[pos++];
                    LineNumber = data_address[pos++];LineNumber <<= 8;//高8位
                    LineNumber |= data_address[pos++];//低8位

                    dLOG("FileTransmit_Finish:object=%s LineNumber=%d\n",dMemory_FileName(object),LineNumber);
                    if(object != eMemory_FileObject_User0){Protocol_CommandSend_General_OneValue(false,Protocol_FrameSendBuffer0,eCommandType_Device,eCodeType_Device_FileTransmit_FinishAck,1);return;}
                    
                    Data_CalibrationDataUse_Set(false);
                    Memory_FileLineNumber_Write((Memory_FileObject_EnumDef )object,LineNumber);
                    Data_CalibrationLoad();

                    uint16_t Read = Memory_FileLineNumber_Read((Memory_FileObject_EnumDef )object);
                    Protocol_CommandSend_General_OneValue(false,Protocol_FrameSendBuffer0,\
                        eCommandType_Device,eCodeType_Device_FileTransmit_FinishAck,\
                        (Read == LineNumber)?0:3);
                }break;
                case eCodeType_Device_OperationInformation_Set:
                {
                    value = data_address[pos++];
                    dLOG("OperationInformation_Set:%s\n",value?"true":"false");
                    OperationInformationPrintf = value?true:false;
                    Protocol_CommandSend_General_NullValue(false,Protocol_FrameSendBuffer0,eCommandType_Device,eCodeType_Device_OperationInformation_Ack);
                }break;
            }
        }break;
        default:return;
    }
}
